# coding=utf-8
# 参数初始化 https://www.mindspore.cn/tutorials/zh-CN/master/advanced/modules/loss.html

# 内置损失函数
import numpy as np
from mindspore import nn
from mindspore import Tensor

# 输出loss均值
loss = nn.L1Loss()
# 输出loss和
loss_sum = nn.L1Loss(reduction='sum')
# 输出loss原值
loss_none = nn.L1Loss(reduction='none')

input_data = Tensor(np.array([[1, 2, 3], [2, 3, 4]]).astype(np.float32))
target_data = Tensor(np.array([[0, 2, 5], [3, 1, 1]]).astype(np.float32))

print("loss:", loss(input_data, target_data))
print("loss_sum:", loss_sum(input_data, target_data))
print("loss_none:", loss_none(input_data, target_data))

# 自定义损失函数
# 基于nn.Cell构造损失函数
from mindspore import ops
import mindspore as ms

class MAELoss(nn.Cell):
    """自定义损失函数MAELoss"""
    def construct(self, base, target):
        return ops.abs(base - target).mean()

loss = MAELoss()

input_data = Tensor(np.array([0.1, 0.2, 0.3]).astype(np.float32))  # 生成预测值
target_data = Tensor(np.array([0.1, 0.2, 0.2]).astype(np.float32)) # 生成真实值

output = loss(input_data, target_data)
print(output)

# 基于nn.LossBase构造损失函数
class MAELoss(nn.LossBase):
    """自定义损失函数MAELoss"""
    def construct(self, base, target):
        x = ops.abs(base - target)
        return self.get_loss(x)  # 返回loss均值

loss = MAELoss()

input_data = Tensor(np.array([0.1, 0.2, 0.3]).astype(np.float32))  # 生成预测值
target_data = Tensor(np.array([0.1, 0.2, 0.2]).astype(np.float32))  # 生成真实值

output = loss(input_data, target_data)
print(output)


# 损失函数与模型训练
from mindspore.train import Model, LossMonitor
from mindspore.dataset import GeneratorDataset

def get_data(num, w=2.0, b=3.0):
    """生成数据及对应标签"""
    for _ in range(num):
        x = np.random.uniform(-10.0, 10.0)
        noise = np.random.normal(0, 1)
        y = x * w + b + noise
        yield np.array([x]).astype(np.float32), np.array([y]).astype(np.float32)

def create_dataset(num_data, batch_size=16):
    """加载数据集"""
    dataset = GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
    dataset = dataset.batch(batch_size)
    return dataset

train_dataset = create_dataset(num_data=160)
network = nn.Dense(1, 1)
loss_fn = MAELoss()
optimizer = nn.Momentum(network.trainable_params(), learning_rate=0.005, momentum=0.9)

# 使用model接口将网络、损失函数和优化器关联起来
model = Model(network, loss_fn, optimizer)
model.train(10, train_dataset, callbacks=[LossMonitor(10)])


# 多标签损失函数与模型训练
def get_multilabel_data(num, w=2.0, b=3.0):
    for _ in range(num):
        x = np.random.uniform(-10.0, 10.0)
        noise1 = np.random.normal(0, 1)
        noise2 = np.random.normal(-1, 1)
        y1 = x * w + b + noise1
        y2 = x * w + b + noise2
        yield np.array([x]).astype(np.float32), np.array([y1]).astype(np.float32), np.array([y2]).astype(np.float32)

def create_multilabel_dataset(num_data, batch_size=16):
    dataset = GeneratorDataset(list(get_multilabel_data(num_data)), column_names=['data', 'label1', 'label2'])
    dataset = dataset.batch(batch_size)  # 每个batch有16个数据
    return dataset

# 多标签损失函数
class MAELossForMultiLabel(nn.LossBase):

    def construct(self, base, target1, target2):
        x1 = ops.abs(base - target1)
        x2 = ops.abs(base - target2)
        return (self.get_loss(x1) + self.get_loss(x2)) / 2


#多标签模型训练

train_dataset = create_multilabel_dataset(num_data=160)

# 定义多标签损失函数
loss_fn = MAELossForMultiLabel()
# 定义优化器
opt = nn.Momentum(network.trainable_params(), learning_rate=0.005, momentum=0.9)



